package services

import (
	"database/sql"
	"fmt"
	"time"

	"miracle-recorder/internal/models"
	"github.com/go-redis/redis/v8"
)

type LivestreamService struct {
	db    *sql.DB
	redis *redis.Client
}

func NewLivestreamService(db *sql.DB, redis *redis.Client) *LivestreamService {
	return &LivestreamService{db: db, redis: redis}
}

func (s *LivestreamService) CreateLivestream(livestream *models.Livestream) error {
	query := `
		INSERT INTO livestreams (title, description, topic_id, streamer_id, rtmp_url, hls_url, 
		                        status, viewer_count, max_viewers, thumbnail, is_recording, tags, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
		RETURNING id
	`

	err := s.db.QueryRow(query,
		livestream.Title,
		livestream.Description,
		livestream.TopicID,
		livestream.StreamerID,
		livestream.RTMPURL,
		livestream.HLSURL,
		livestream.Status,
		livestream.ViewerCount,
		livestream.MaxViewers,
		livestream.Thumbnail,
		livestream.IsRecording,
		livestream.Tags,
		time.Now(),
		time.Now(),
	).Scan(&livestream.ID)

	if err != nil {
		return fmt.Errorf("failed to create livestream: %w", err)
	}

	return nil
}

func (s *LivestreamService) GetLivestream(id int) (*models.Livestream, error) {
	query := `
		SELECT l.id, l.title, l.description, l.topic_id, l.streamer_id, l.rtmp_url, l.hls_url,
		       l.status, l.viewer_count, l.max_viewers, l.start_time, l.end_time, l.duration,
		       l.thumbnail, l.recording_url, l.is_recording, l.tags, l.created_at, l.updated_at,
		       u.id, u.username, u.email, u.avatar, u.bio, u.created_at, u.updated_at,
		       t.id, t.title, t.description, t.creator_id, t.category, t.tags,
		       t.ai_summary, t.credibility_score, t.view_count, t.like_count, t.comment_count,
		       t.share_count, t.status, t.created_at, t.updated_at
		FROM livestreams l
		LEFT JOIN users u ON l.streamer_id = u.id
		LEFT JOIN topics t ON l.topic_id = t.id
		WHERE l.id = $1
	`

	livestream := &models.Livestream{}
	var streamerUser models.User
	var topicData models.Topic

	err := s.db.QueryRow(query, id).Scan(
		&livestream.ID,
		&livestream.Title,
		&livestream.Description,
		&livestream.TopicID,
		&livestream.StreamerID,
		&livestream.RTMPURL,
		&livestream.HLSURL,
		&livestream.Status,
		&livestream.ViewerCount,
		&livestream.MaxViewers,
		&livestream.StartTime,
		&livestream.EndTime,
		&livestream.Duration,
		&livestream.Thumbnail,
		&livestream.RecordingURL,
		&livestream.IsRecording,
		&livestream.Tags,
		&livestream.CreatedAt,
		&livestream.UpdatedAt,
		&streamerUser.ID,
		&streamerUser.Username,
		&streamerUser.Email,
		&streamerUser.Avatar,
		&streamerUser.Bio,
		&streamerUser.CreatedAt,
		&streamerUser.UpdatedAt,
		&topicData.ID,
		&topicData.Title,
		&topicData.Description,
		&topicData.CreatorID,
		&topicData.Category,
		&topicData.Tags,
		&topicData.AISummary,
		&topicData.CredibilityScore,
		&topicData.ViewCount,
		&topicData.LikeCount,
		&topicData.CommentCount,
		&topicData.ShareCount,
		&topicData.Status,
		&topicData.CreatedAt,
		&topicData.UpdatedAt,
	)

	if err != nil {
		if err == sql.ErrNoRows {
			return nil, fmt.Errorf("livestream not found")
		}
		return nil, fmt.Errorf("failed to get livestream: %w", err)
	}

	livestream.Streamer = streamerUser
	livestream.Topic = topicData
	return livestream, nil
}

func (s *LivestreamService) ListLivestreams(limit, offset int, status string) ([]*models.Livestream, error) {
	query := `
		SELECT l.id, l.title, l.description, l.topic_id, l.streamer_id, l.rtmp_url, l.hls_url,
		       l.status, l.viewer_count, l.max_viewers, l.start_time, l.end_time, l.duration,
		       l.thumbnail, l.recording_url, l.is_recording, l.tags, l.created_at, l.updated_at,
		       u.id, u.username, u.email, u.avatar, u.bio, u.created_at, u.updated_at,
		       t.id, t.title, t.description, t.creator_id, t.category, t.tags,
		       t.ai_summary, t.credibility_score, t.view_count, t.like_count, t.comment_count,
		       t.share_count, t.status, t.created_at, t.updated_at
		FROM livestreams l
		LEFT JOIN users u ON l.streamer_id = u.id
		LEFT JOIN topics t ON l.topic_id = t.id
		WHERE l.status = $1
		ORDER BY l.created_at DESC
		LIMIT $2 OFFSET $3
	`

	rows, err := s.db.Query(query, status, limit, offset)
	if err != nil {
		return nil, fmt.Errorf("failed to list livestreams: %w", err)
	}
	defer rows.Close()

	var livestreams []*models.Livestream
	for rows.Next() {
		livestream := &models.Livestream{}
		var streamerUser models.User
		var topicData models.Topic

		err := rows.Scan(
			&livestream.ID,
			&livestream.Title,
			&livestream.Description,
			&livestream.TopicID,
			&livestream.StreamerID,
			&livestream.RTMPURL,
			&livestream.HLSURL,
			&livestream.Status,
			&livestream.ViewerCount,
			&livestream.MaxViewers,
			&livestream.StartTime,
			&livestream.EndTime,
			&livestream.Duration,
			&livestream.Thumbnail,
			&livestream.RecordingURL,
			&livestream.IsRecording,
			&livestream.Tags,
			&livestream.CreatedAt,
			&livestream.UpdatedAt,
			&streamerUser.ID,
			&streamerUser.Username,
			&streamerUser.Email,
			&streamerUser.Avatar,
			&streamerUser.Bio,
			&streamerUser.CreatedAt,
			&streamerUser.UpdatedAt,
			&topicData.ID,
			&topicData.Title,
			&topicData.Description,
			&topicData.CreatorID,
			&topicData.Category,
			&topicData.Tags,
			&topicData.AISummary,
			&topicData.CredibilityScore,
			&topicData.ViewCount,
			&topicData.LikeCount,
			&topicData.CommentCount,
			&topicData.ShareCount,
			&topicData.Status,
			&topicData.CreatedAt,
			&topicData.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan livestream: %w", err)
		}

		livestream.Streamer = streamerUser
		livestream.Topic = topicData
		livestreams = append(livestreams, livestream)
	}

	return livestreams, nil
}

func (s *LivestreamService) StartLivestream(id int) error {
	now := time.Now()
	query := `
		UPDATE livestreams
		SET status = 'live', start_time = $1, updated_at = $2
		WHERE id = $3 AND status = 'pending'
	`

	result, err := s.db.Exec(query, now, now, id)
	if err != nil {
		return fmt.Errorf("failed to start livestream: %w", err)
	}

	if rowsAffected, _ := result.RowsAffected(); rowsAffected == 0 {
		return fmt.Errorf("livestream not found or already started")
	}

	return nil
}

func (s *LivestreamService) StopLivestream(id int) error {
	now := time.Now()
	query := `
		UPDATE livestreams
		SET status = 'ended', end_time = $1, duration = EXTRACT(EPOCH FROM ($1 - start_time))::INTEGER, updated_at = $2
		WHERE id = $3 AND status = 'live'
	`

	result, err := s.db.Exec(query, now, now, id)
	if err != nil {
		return fmt.Errorf("failed to stop livestream: %w", err)
	}

	if rowsAffected, _ := result.RowsAffected(); rowsAffected == 0 {
		return fmt.Errorf("livestream not found or not live")
	}

	return nil
}

func (s *LivestreamService) UpdateViewerCount(id int, count int) error {
	query := `
		UPDATE livestreams
		SET viewer_count = $1, updated_at = $2
		WHERE id = $3
	`

	_, err := s.db.Exec(query, count, time.Now(), id)
	if err != nil {
		return fmt.Errorf("failed to update viewer count: %w", err)
	}

	return nil
}

type InteractionService struct {
	db    *sql.DB
	redis *redis.Client
}

func NewInteractionService(db *sql.DB, redis *redis.Client) *InteractionService {
	return &InteractionService{db: db, redis: redis}
}

func (s *InteractionService) CreateInteraction(interaction *models.Interaction) error {
	query := `
		INSERT INTO interactions (topic_id, user_id, type, content, media_url, media_type, parent_id, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
		RETURNING id
	`

	err := s.db.QueryRow(query,
		interaction.TopicID,
		interaction.UserID,
		interaction.Type,
		interaction.Content,
		interaction.MediaURL,
		interaction.MediaType,
		interaction.ParentID,
		time.Now(),
		time.Now(),
	).Scan(&interaction.ID)

	if err != nil {
		return fmt.Errorf("failed to create interaction: %w", err)
	}

	return nil
}

func (s *InteractionService) GetInteractionsByTopic(topicID int, limit, offset int) ([]*models.Interaction, error) {
	query := `
		SELECT i.id, i.topic_id, i.user_id, i.type, i.content, i.media_url, i.media_type,
		       i.parent_id, i.reply_count, i.like_count, i.created_at, i.updated_at,
		       u.id, u.username, u.email, u.avatar, u.bio, u.created_at, u.updated_at
		FROM interactions i
		LEFT JOIN users u ON i.user_id = u.id
		WHERE i.topic_id = $1
		ORDER BY i.created_at ASC
		LIMIT $2 OFFSET $3
	`

	rows, err := s.db.Query(query, topicID, limit, offset)
	if err != nil {
		return nil, fmt.Errorf("failed to get interactions: %w", err)
	}
	defer rows.Close()

	var interactions []*models.Interaction
	for rows.Next() {
		interaction := &models.Interaction{}
		var user models.User

		err := rows.Scan(
			&interaction.ID,
			&interaction.TopicID,
			&interaction.UserID,
			&interaction.Type,
			&interaction.Content,
			&interaction.MediaURL,
			&interaction.MediaType,
			&interaction.ParentID,
			&interaction.ReplyCount,
			&interaction.LikeCount,
			&interaction.CreatedAt,
			&interaction.UpdatedAt,
			&user.ID,
			&user.Username,
			&user.Email,
			&user.Avatar,
			&user.Bio,
			&user.CreatedAt,
			&user.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan interaction: %w", err)
		}

		interaction.User = user
		interactions = append(interactions, interaction)
	}

	return interactions, nil
}